#!/usr/bin/env python3

'''
Basic IPv4 router (static routing) in Python.
'''

import sys
import os
import time
from switchyard.lib.userlib import *

class Router(object):
    def __init__(self, net):
        self.net = net
        # other initialization stuff here
        self.arp_table = {} #ip -> mac
        self.age_table = {} #ip -> age
        self.router_interfaces = {}
        for intf in net.interfaces():
            self.router_interfaces[intf.name] = intf.ipaddr


    def router_main(self):    
        '''
        Main method for router; we stay in a loop in this method, receiving
        packets until the end of time.
        '''
        while True:
            gotpkt = True
            try:
                timestamp,dev,pkt = self.net.recv_packet(timeout=1.0)
            except NoPackets:
                log_debug("No packets available in recv_packet")
                gotpkt = False
            except Shutdown:
                log_debug("Got shutdown signal")
                break
            
            if gotpkt:
                log_debug("Got a packet: {}".format(str(pkt)))
                # TODO: get APR packet
                if(pkt.has_header(Arp)):
                    arp = pkt.get_header(Arp)

                    # TODO: add or update request information to arp table
                    if arp.senderprotoaddr not in self.arp_table.keys():
                        index = None #index of the port to remove
                        for i in self.age_table:
                            self.age_table[i] += 1
                            if self.age_table[i] >= 3:
                                index = i
                        if index is not None: #table_age is not fall
                            self.age_table.pop(index) #remove it
                            self.arp_table.pop(index)
                        self.arp_table[arp.senderprotoaddr] = arp.senderhwaddr
                        self.age_table[arp.senderprotoaddr] = 0
                    else:
                        self.arp_table[arp.senderprotoaddr] = arp.senderhwaddr
                        for i in self.age_table.keys():
                            if self.age_table[i] < self.age_table[arp.senderprotoaddr]:
                                self.age_table[i] += 1
                        self.age_table[arp.senderprotoaddr] = 0

                    # TODO: print arp_table
                    for key,value in self.arp_table.items():
                        log_info('{key}: {value}'.format(key = key, value = value))
                    log_info("\n")

                    # TODO: get APR request
                    if arp.operation == 1:
                        # TODO: APR reply is dst in router interface
                        if arp.targetprotoaddr in self.router_interfaces.values():
                            reply = create_ip_arp_reply(self.net.interface_by_ipaddr(arp.targetprotoaddr).ethaddr, arp.senderhwaddr, arp.targetprotoaddr, arp.senderprotoaddr)
                            self.net.send_packet(self.net.interface_by_name(dev), reply)


def main(net):
    '''
    Main entry point for router.  Just create Router
    object and get it going.
    '''
    r = Router(net)
    r.router_main()
    net.shutdown()
